package com.wpam.scrabble.mobile.ui;

import java.util.ArrayList;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
import android.widget.Toast;

import com.wpam.scrabble.mobile.MoveInfo;
import com.wpam.scrabble.mobile.GameLogic;
import com.wpam.scrabble.mobile.GameData;
import com.wpam.scrabble.mobile.GameResources;
import com.wpam.scrabble.mobile.MovePart;
import com.wpam.scrabble.mobile.R;
import com.wpam.scrabble.mobile.activities.BoardActivity;

public class GameBoard extends ImageView implements OnTouchListener {

	private static final int INVALID_POINTER_ID = -1;

	private BoardActivity parentActivity_;

	private LettersStand lettersStand_;
	
	private Paint paint_;
	private ArrayList<SquareBitmap> squares_;
	private int tileSize_;

	private float xPos_;
	private float yPos_;

	private float xLastTouch_;
	private float yLastTouch_;

	private float xScale_;
	private float yScale_;
	private float scaleFactor_;
	private int activePointerId_;
	private ScaleGestureDetector scaleDetector_;
	
	private int currentlyHighlited_;
	
	private LetterChangePanel letterChangePanel_;
	private boolean drawLetterChangePanel_;

	public GameBoard(Context context, AttributeSet attrs) {
		
		super(context, attrs);
		GameResources.getInstance(context);
		this.parentActivity_ = null;
		this.lettersStand_ = new LettersStand();
		this.paint_ = new Paint();
		this.paint_.setColor(Color.rgb(23, 176, 5));
		this.tileSize_ = SquareBitmap.DEFAULT_SIZE;
		this.xPos_ = 0;
		this.yPos_ = 0;
		this.xLastTouch_ = 0;
		this.yLastTouch_ = 0;
		this.xScale_ = 0;
		this.yScale_ = 0;
		this.scaleFactor_ = 1.f;
		this.activePointerId_ = INVALID_POINTER_ID;
		this.scaleDetector_ = new ScaleGestureDetector(context, new ScaleListener());
		this.currentlyHighlited_ = -1;
		this.letterChangePanel_ = new LetterChangePanel();
		this.drawLetterChangePanel_ = false;
		this.squares_ = new ArrayList<SquareBitmap>(255);
		for (int i = 0; i < 15; ++i) {
			for (int j = 0; j < 15; j++) {
				if ((i == 0 || i == 14 || i == 7)
						&& (j == 0 || j == 7 || j == 14)
						&& (i == 0 || j == 0 || j == 14 || i == 14)) {
					// premia s�owna x3
					squares_.add(new SquareBitmap(tileSize_ * i, tileSize_ * j, SquareBitmap.WORDx3));
				} else if ((i == j || i == 14 - j) && (i < 5 || i > 9)
						|| (i == 7 && j == 7)) {
					// premia s�owna x2
					squares_.add(new SquareBitmap(tileSize_ * i, tileSize_ * j, SquareBitmap.WORDx2));
				} else if ((i == 1 || i == 5 || i == 9 || i == 13)
						&& (j == 1 || j == 5 || j == 9 || j == 13)) {
					// premia literowa x3
					squares_.add(new SquareBitmap(tileSize_ * i, tileSize_ * j, SquareBitmap.LETTERx3));
				} else if (((i == 0 || i == 3 || i == 7 || i == 11 || i == 14) && (j == 0
						|| j == 3 || j == 7 || j == 11 || j == 14))
						|| ((i == 2 || i == 6 || i == 8 || i == 12) && (j == 2
								|| j == 6 || j == 8 || j == 12))) {
					// premia literowa x2
					squares_.add(new SquareBitmap(tileSize_ * i, tileSize_ * j, SquareBitmap.LETTERx2));
				} else {
					squares_.add(new SquareBitmap(tileSize_ * i, tileSize_ * j, SquareBitmap.NORMAL));
				}
			}
		}
		setOnTouchListener(this);
	}

	public void setParentActivity(BoardActivity parent) {
		this.parentActivity_ = parent;
	}
	
	@Override
	public void onDraw(Canvas canvas) {

		canvas.save();

		canvas.translate(xPos_, yPos_);
		canvas.scale(scaleFactor_, scaleFactor_, xScale_, yScale_);

		super.onDraw(canvas);
		canvas.drawRect(0, 0, 15 * tileSize_, 15 * tileSize_, paint_);
		for (SquareBitmap squareBitmap : squares_)
			squareBitmap.draw(canvas);

		canvas.restore();
		lettersStand_.draw(canvas);
		
		if (drawLetterChangePanel_)
			letterChangePanel_.draw(canvas);
	}

	private void highlight(int posX, int posY) {

		int row = (int) posY/tileSize_;
		int col = (int) posX/tileSize_;
		unhighlight();
		if (row < 0 || row > 14 || col < 0 || col > 14)
			return;
		currentlyHighlited_ = row + 15 * col;
		squares_.get(currentlyHighlited_).highlight(true);
	}
	
	private void unhighlight() {
		
		if (currentlyHighlited_ >= 0 && currentlyHighlited_ < squares_.size())
			squares_.get(currentlyHighlited_).highlight(false);
	}
	
	public void applyMove(MoveInfo currentMove) {
		
		for (MovePart movePart : currentMove.getLetters()) {
			getSquare(movePart.getRow(), movePart.getCol()).setLetter(movePart.getLetter());
			getSquare(movePart.getRow(), movePart.getCol()).setAccepted();
		}
	}
	
	public void cancelCurrentMove() {

		MoveInfo curr = GameLogic.getInstance().getCurrentMove();
		if (curr.getLetters() != null) {
			for (MovePart movePart : curr.getLetters())
				getSquare(movePart.getRow(), movePart.getCol()).reset();
		}
		curr.resetMove();
		lettersStand_.reset();
		postInvalidate();
	}
	
	public void acceptNewLetters(String letters) {
		
		lettersStand_.setLetters(letters);
		postInvalidate();
	}

	private LettersStandSquare lastPickedSquare_ = null;
	private boolean canTranslate_ = true;
			
	public boolean onTouch(View v, MotionEvent event) {
		
		if (drawLetterChangePanel_) {
			if (event.getAction() == MotionEvent.ACTION_DOWN)
				letterChangePanel_.handleClick((int) event.getX(), (int) event.getY());
		} else {
			float objectNewX, objectNewY;
			if (scaleFactor_ >= 1) {
			    objectNewX = -xPos_ + event.getX();
			    objectNewY = -yPos_ + event.getY();
			} else {
			    objectNewX = -xPos_ + event.getX();
			    objectNewY = -yPos_ + event.getY();
			}
			
			boolean isOnLetterStand = (getHeight() - event.getY() < lettersStand_.getHeight()); 
			
			switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				canTranslate_ = !isOnLetterStand;
				if (isOnLetterStand) {
					if (GameLogic.getInstance().isMyTurn() && !GameLogic.getInstance().isGamePaused()) {
						lastPickedSquare_ = lettersStand_.getSquare((int) event.getX(), (int) event.getY());
						invalidate();
					} else
						Toast.makeText(getContext(), getResources().getString(R.string.it_is_not_your_turn), Toast.LENGTH_SHORT).show();
				}
				break;
			case MotionEvent.ACTION_MOVE:
				if (lastPickedSquare_ != null) {
					lastPickedSquare_.setPos((int) event.getX() - lastPickedSquare_.getPickedOffsetX(), (int) event.getY() - lastPickedSquare_.getPickedOffsetY());
					if (!isOnLetterStand)
						highlight((int) objectNewX, (int) objectNewY);
					else 
						unhighlight();
				}
				invalidate();
				break;
			case MotionEvent.ACTION_UP:
				if (lastPickedSquare_ != null) {
					boolean status = false;
					if (!isOnLetterStand) {
						lastPickedSquare_.setPos((int) event.getX(), (int) event.getY());
						int row = (int) objectNewY/tileSize_;
						int col = (int) objectNewX/tileSize_;
						if (row >= 0 && row < 15 && col >= 0 && col < 15) {
							status = getSquare(row, col).setLetter(lastPickedSquare_.getLetter());
							GameLogic.getInstance().getCurrentMove().insertLetter(new MovePart(row, col, lastPickedSquare_.getLetter(), lastPickedSquare_.getPoints()));
						}
					}
					lastPickedSquare_.putDown(status);
					unhighlight();
				}
				invalidate();
				lastPickedSquare_ = null;
				break;
			}
	
			if (lastPickedSquare_ == null) {
				scaleDetector_.onTouchEvent(event);
	
				switch (event.getAction() & MotionEvent.ACTION_MASK) {
				case MotionEvent.ACTION_DOWN: {
					final float x = event.getX();
					final float y = event.getY();
					
					xLastTouch_ = x;
					yLastTouch_ = y;
					activePointerId_ = event.getPointerId(0);
					break;
				}
				
				case MotionEvent.ACTION_MOVE: {
					final int pointerIndex = event
							.findPointerIndex(activePointerId_);
					if (pointerIndex == -1) 
						break;
					final float x = event.getX(pointerIndex);
					final float y = event.getY(pointerIndex);
	
					// Only move if the ScaleGestureDetector isn't processing a
					// gesture.
					if (!scaleDetector_.isInProgress() && canTranslate_) {
						final float dx = x - xLastTouch_;
						final float dy = y - yLastTouch_;
	
						xPos_ += dx;
						yPos_ += dy;
						invalidate();
					}
	
					xLastTouch_ = x;
					yLastTouch_ = y;
					break;
				}
	
				case MotionEvent.ACTION_UP: {
					activePointerId_ = INVALID_POINTER_ID;
					break;
				}
	
				case MotionEvent.ACTION_CANCEL: {
					activePointerId_ = INVALID_POINTER_ID;
					break;
				}
	
				case MotionEvent.ACTION_POINTER_UP: {
					final int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
					final int pointerId = event.getPointerId(pointerIndex);
					if (pointerId == activePointerId_) {
						final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
						xLastTouch_ = event.getX(newPointerIndex);
						yLastTouch_ = event.getY(newPointerIndex);
						activePointerId_ = event.getPointerId(newPointerIndex);
					}
					break;
				}
				}
			}
		}
		return true;
	}

	private class ScaleListener extends
			ScaleGestureDetector.SimpleOnScaleGestureListener {
		
		@Override
		public boolean onScale(ScaleGestureDetector detector) {
			scaleFactor_ *= detector.getScaleFactor();

			scaleFactor_ = Math.max(0.1f, Math.min(scaleFactor_, 2.0f));
			xScale_ = detector.getFocusX();
			yScale_ = detector.getFocusY();

			invalidate();
			return true;
		}
	}

	public SquareBitmap getSquare(int row, int col) {
		return squares_.get(row + 15 * col);
	}

	public void showLetterChangePanel(boolean visible) {
		
		if (visible)
			letterChangePanel_.setLetters(lettersStand_);
		drawLetterChangePanel_ = visible;
		invalidate();
	}

	public void takeAwayLetters(String letters) {
		lettersStand_.takeAwayLetters(letters);
	}

	public void finishBoardActivity() {
		parentActivity_.finish();
	}

	public Activity getParentActivity() {
		return parentActivity_;
	}

	public void resize() {
		lettersStand_.resize();
		letterChangePanel_.resize();
	}

	public void startMyTurn(boolean myTurn) {
		
		if (myTurn)
			lettersStand_.setColorFilter(null);
		else 
			lettersStand_.setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);
	}
	
	public void applyGameData(GameData gameData) {
		
		lettersStand_.setLetters(gameData.getUserLetters());
		for (MovePart letter : gameData.getLetters()) {
			getSquare(letter.getRow(), letter.getCol()).setLetter(letter.getLetter());
			getSquare(letter.getRow(), letter.getCol()).setAccepted();
		}
	}
}
